#include <gtk-3.0/gdk/gdk.h>
#include <gtk-3.0/gdk/gdkx.h>
#include <gtk-3.0/gdk/gdkwayland.h>
#include <gtk-3.0/gdk/gdkwindow.h>

#include <stdio.h>
#include <assert.h>

static void print_display(GdkDisplay *display)
{
#ifdef GDK_WINDOWING_X11
    if (GDK_IS_X11_DISPLAY(display))
    {
        g_print("use X11\n");
    }
#endif    

#ifdef GDK_WINDOWING_WAYLAND
    if (GDK_IS_WAYLAND_DISPLAY(display))
    {
        g_print("use WAYLAND\n");
    }
#endif    

#ifdef GDK_WINDOWING_WIN32
    if (GDK_IS_WIN32_DISPLAY(display))
    {
        g_print("use WIN32\n");
    }
#endif    

    g_print("display_name=%s\n", gdk_display_get_name(display));
    g_print("default cursor size= %d\n", gdk_display_get_default_cursor_size(display));
}

static void print_screen(GdkDisplay *display)
{
    GdkScreen *screen;
    screen = gdk_display_get_default_screen(display);

    g_print("screen is composited, %s\n", gdk_screen_is_composited(screen) ? "Yes":"No" );
    g_print("screen resolution, %f dpi\n", gdk_screen_get_resolution(screen));

}

static void print_device(GdkDevice *device)
{
  g_assert(device);

  GList *list;
  GList *itr;

  const gchar *vendor, *product;


  switch(gdk_device_get_device_type(device))
  {
      case GDK_DEVICE_TYPE_MASTER:
        g_print("device name: %s\t\t(master)\n", gdk_device_get_name(device));
        list = gdk_device_list_slave_devices(device);
        for(itr = list; itr; itr= itr->next)
        {
            print_device((GdkDevice*)itr->data);
        }

        break;
      case GDK_DEVICE_TYPE_SLAVE:
        g_print("\t %s\t\t(slave)\n", gdk_device_get_name(device));
        vendor = gdk_device_get_vendor_id (device);
        product = gdk_device_get_product_id (device);
        g_print("\t\t vendor=%s, product=%s\n", vendor, product);
        break;
      case GDK_DEVICE_TYPE_FLOATING:
        g_print("\t %s\t\t(floating)\n", gdk_device_get_name(device));
        vendor = gdk_device_get_vendor_id (device);
        product = gdk_device_get_product_id (device);
        g_print("\t\t vendor=%s, product=%s\n", vendor, product);
        break;
  }
//   g_print("device: vendor=%s, product=%s\n", vendor, product);
}

static void print_seat(GdkDisplay *display)
{
    GdkSeat *seat;
    seat = gdk_display_get_default_seat(display);
    
    GdkSeatCapabilities cap;
    cap = gdk_seat_get_capabilities (seat);

    g_print("seat capabilities: ");    
    if(cap & GDK_SEAT_CAPABILITY_POINTER)
        g_print("Pointer ");
    if(cap & GDK_SEAT_CAPABILITY_KEYBOARD)
        g_print("Keyboard ");
    if(cap & GDK_SEAT_CAPABILITY_TOUCH)
        g_print("Touch ");
    if(cap & GDK_SEAT_CAPABILITY_TABLET_STYLUS)
        g_print("Tablet ");
    g_print("\n");

    print_device(gdk_seat_get_keyboard(seat));
    print_device(gdk_seat_get_pointer(seat));
}

static void print_monitor(GdkDisplay *display)
{
    int count;
    int i;
    count = gdk_display_get_n_monitors(display);
    for(i = 0; i< count; i++)
    {
        GdkMonitor *monitor = gdk_display_get_monitor(display, i);
        g_print("monitor %d: model=%s, manufacturer=%s\n", i, gdk_monitor_get_model(monitor), gdk_monitor_get_manufacturer(monitor));
        
        if(gdk_monitor_is_primary(monitor))
            g_print("\tprimary\n");

        GdkRectangle geometry;
        GdkRectangle workarea;
        gdk_monitor_get_geometry(monitor, &geometry);
        gdk_monitor_get_workarea(monitor, &workarea);
        g_print("\tgeometry: (%d,%d), %dX%d appPixel\n"
                        , geometry.x, geometry.y
                        , geometry.width, geometry.height);
        g_print("\tworkarea: (%d,%d), %dX%d appPixel\n"
                        , workarea.x, workarea.y
                        , workarea.width, workarea.height);
        g_print("\tmm: %dX%d\n"
                        , gdk_monitor_get_width_mm(monitor)
                        , gdk_monitor_get_height_mm(monitor));
        g_print("\tscaleFactor: %d, refreshRate: %d\n"
                        , gdk_monitor_get_scale_factor(monitor)
                        , gdk_monitor_get_refresh_rate(monitor));

        static gchar* subpixleLayoutName[]={
                "unknown", // GDK_SUBPIXEL_LAYOUT_UNKNOWN,
                "none", // GDK_SUBPIXEL_LAYOUT_NONE,
                "horizontal_rgb", // GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB,
                "horizontal_bgr", // GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR,
                "vertical_rgb", // GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB,
                "vertical_bgr", // GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR
        };

        g_print("\tsubpixelLayout: %s\n", subpixleLayoutName[gdk_monitor_get_subpixel_layout(monitor)]);
    }
}

static void print_visual(GdkVisual *visual)
{
    guint32 mask;
    gint shift;
    gint precision;

    gdk_visual_get_red_pixel_details(visual, &mask, &shift, &precision);
    g_print("\tred pixel: 0x%x, 0x%x, 0x%x\n", mask, shift, precision);
    gdk_visual_get_green_pixel_details(visual, &mask, &shift, &precision);
    g_print("\tgreen pixel: 0x%x, 0x%x, 0x%x\n", mask, shift, precision);
    gdk_visual_get_blue_pixel_details(visual, &mask, &shift, &precision);
    g_print("\tblue pixel: 0x%x, 0x%x, 0x%x\n", mask, shift, precision);

    // g_print("\tbyte order: %s\n", ((gdk_visual_get_byte_order(visual) == GDK_LSB_FIRST) ? "LSB first" : "MSB first"));
    g_print("\tdepth: %d\n", gdk_visual_get_depth(visual));

    g_print("\tvisual type: ");
    switch(gdk_visual_get_visual_type(visual))
    {
        case GDK_VISUAL_STATIC_GRAY:
            g_print("GRAY\n");
            break;
        case GDK_VISUAL_GRAYSCALE:
            g_print("GRAYSCALE\n");
            break;
        case GDK_VISUAL_STATIC_COLOR:
            g_print("STATIC_COLOR\n");
            break;
        case GDK_VISUAL_PSEUDO_COLOR:
            g_print("PSEUDO_COLOR\n");
            break;
        case GDK_VISUAL_TRUE_COLOR:
            g_print("TRUE_COLOR\n");
            break;
        case GDK_VISUAL_DIRECT_COLOR:
            g_print("DIRECT_COLOR\n");
            break;
    }

    
}

static void print_visuals(GdkDisplay *display)
{
    GdkScreen *screen = gdk_display_get_default_screen(display);
    GdkVisual *visual;
    
    visual = gdk_screen_get_system_visual(screen);
    g_print("System Visual:\n");
    print_visual(visual);

    visual = gdk_screen_get_rgba_visual(screen);
    g_print("rgba Visual:\n");
    print_visual(visual);

    
}

int main(int argc, char* argv[])
{
    gboolean ok;

    g_print("main()....\n");

    // g_setenv ("DISPLAY", ":0.0", TRUE);
    ok = gdk_init_check(&argc, &argv);
    // ok = gdk_init_check(NULL, NULL);
    g_assert(ok);

    g_print("display_arg_name=%s\n", gdk_get_display_arg_name());       // '--display=XXX' cmdline option, or DISPLAY env
    g_print("program_class=%s\n", gdk_get_program_class());             // '--class=XXX' cmdline option
    g_print("prg_name=%s\n", g_get_prgname());
    g_print("support X11: ");
#ifdef GDK_WINDOWING_X11
    g_print("X11 ");
#endif        
#ifdef GDK_WINDOWING_WIN32
    g_print("WIN32 ");
#endif        
#ifdef GDK_WINDOWING_QUARTZ
    g_print("QUARTZ ");
#endif        
#ifdef GDK_WINDOWING_WAYLAND
    g_print("WAYLAND ");
#endif        
    g_print("\n");
    

    GdkDisplayManager *gdm;
    GdkDisplay *display;

    gdm = gdk_display_manager_get();

    GSList *list;
    list = gdk_display_manager_list_displays(gdm);

    GSList *itr;
    int i;
    for(itr = list, i = 1; itr; itr = itr->next, i++)
    {
        g_print("%d: display_name=%s\n", i, gdk_display_get_name((GdkDisplay*)itr->data));

    }
    g_slist_free(list);





    // display = gdk_display_manager_get_default_display(gdm);
    display = gdk_display_open(NULL);       //取default display
    g_assert(display);

    print_display(display);

    print_screen(display);
    print_seat(display);
    print_monitor(display);
    print_visuals(display);

    gdk_display_close(display);
    return 0;
}
